<?
class R_N {
	//  In (320x240 -> 64x48) - Hid (384) - Out ( 8 -> Pr - Ps - Co - Gt - Obj - Rd - Ds)
	private $h=0.5;
	
	const file='pesos_rn.txt';
	private $nn=array(3, 3, 3, 1);
	public $n=array(); // Sum.Neurona
	public $f=array(); // Sigmoid.Sum.Neurona
	public $e=array(); // Error
	
	public $w=array(); // Peso [capa][origen][destino]
	private $peso_ant=array(); // peso[capa][origen][destino]
	
	private function sigmoid($z)	{
		return (double)(1.0 / (1.0 + exp(-$z)));
	}
	
	private function d_sigmoid($z) {
		$t=$this->sigmoid($z);
		return $t*(1-$t);
	}
	
	public function entrada($datos) {
		for ($n=0; $n<$this->nn[0]; $n++) {
			$this->f[0][$n] = $datos[$n];
		}
	}
	
	public function pesos_aleat() {
		$capas=count($this->nn)-1;
		for ($c=0; $c<$capas; $c++) {
			for ($n=0; $n<$this->nn[$c]; $n++) {				
				for ($m=0; $m<$this->nn[$c+1]; $m++) {
					$this->w[$c][$n][$m]=rand(1,1000)/1000;
				}
			}
		}
	}
	
	public function feed_forward() {
		$capas=count($this->nn)-1;
		for ($c=0; $c<$capas; $c++) {
			for ($n=0; $n<$this->nn[$c+1]; $n++) {
				$t=0;
				for ($m=0; $m<$this->nn[$c]; $m++) {
					//echo ($c-1)."$n -> $c$m\r\n";
					$t+=$this->f[$c][$m]*$this->w[$c][$m][$n];
				}
				$this->n[$c+1][$n]=$t;
				$this->f[$c+1][$n]=$this->sigmoid($t);
			}
		}
	}
	
	public function salida($z) {
		$ultima_capa=count($this->nn)-1; // Nivel ultima capa
		$n_ultima_capa=$this->nn[$ultima_capa]; // Neuronas en la última capa
		for ($i=0; $i<$n_ultima_capa; $i++) {
			$u=$this->f[$ultima_capa][$i];
			//echo $z[$i]."-".$u." = ".($z[$i]-$u)."\r\n";
			$this->error[$ultima_capa][$i]=($z[$i]-$u); // Error = Z - Y
		}
	}
	
	public function back_prop() {
		$ultima_capa=count($this->nn)-2; // Nivel ultima capa
		for ($c=$ultima_capa; $c>-1; $c--) {
			for ($n=0; $n<$this->nn[$c]; $n++) {
				$delta=0.0;
				for ($m=0; $m<$this->nn[$c+1]; $m++) {
					//echo "Error de la neurona $c$m / peso $c$m$n ";
					$delta+=$this->error[$c+1][$m]*$this->w[$c][$n][$m];
				}
				//$u=$this->f[$c][$n];
				$this->error[$c][$n]=$delta;
			}
		}
		//echo "Error:";
		//print_r($this->error);
		//echo "\r\n";
	}
	
	public function act_coefs() {
		$capas=count($this->nn)-1;
		for ($c=0; $c<$capas; $c++) {
			for ($n=0; $n<$this->nn[$c]; $n++) {
				for ($m=0; $m<$this->nn[$c-1]; $m++) {
					// h * error (n) * df(n) * n[m]
					$this->w[$c][$n][$m]+=$this->h*$this->error[$c][$n]*$this->n[$c][$m]*$this->d_sigmoid($this->n[$c][$n])*$this->n[$c][$n];
				}
			}
		}
	}
	
}
$data=array(0=>array(0,	0,	1,	array(1)),
			1=>array(0,	0,	0,	array(0)),
			2=>array(0,	1,	0,	array(1)),
			3=>array(0,	1,	1,	array(0)),
			4=>array(1,	0,	0,	array(1)),
			5=>array(1,	0,	1,	array(0)),
			6=>array(1,	1,	0,	array(0)),
			7=>array(1,	1,	1,	array(1))
			);

$rn = new R_N;
$rn->pesos_aleat();
for ($i=0; $i<100; $i++) {
	$error=0;
	for ($j=0; $j<100; $j++) {
		for ($d=0; $d<8; $d++) {
			$rn->entrada($data[$d]);
			$rn->feed_forward();
			$rn->salida($data[$d][3]);
			$rn->back_prop();
			$rn->act_coefs();
		}
		$error+=$rn->error[3][0];
	}
	echo "$i\t".($error)."\r\n";
	//print_r($rn->w);
}

for ($d=0; $d<8; $d++) {
	$rn->entrada($data[$d]);
	$rn->feed_forward();
	$rn->salida($data[$d][3]);
	echo "\r\nSalida ".(($rn->n[3][0]>.5)?1:0)." esperada: ".$data[$d][3][0]."\r\n";
}

	//print_r($rn->error);
	//echo $rn->error[3][0]."\r\n";
//echo $error-$rn->error[3][0]."\r\n";
exit(0);

//print_r($rn->peso);
$rn->feed_forward();
$rn->salida($data[0][3]);
$rn->back_prop();
echo $rn->error[3][0]."\r\n";

//print_r($rn->neurona)

?>